using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace DataPaper
{
    static class ToImg
    {
        static byte[] ToByte(UInt32 i)
        {
            byte[] res = new byte[4];
            for (uint j = 0; j < 4; ++j)
            {
                uint k = i % 256u;
                i /= 256;
                res[j] = (byte)k;
            }
            return res;
        }
        
        static void SelfChange(List<byte> lenData, string str)
        {
            byte[] rng = new byte[lenData.Count];
            new Random(str.GetHashCode()).NextBytes(rng);
            for (int i = 0; i < lenData.Count; ++i)
                lenData[i] ^= rng[i];
        }

        //[0 1 2 3] 4 9 14 19
        static List<byte> FourMore(List<byte> lstChanged)
        {
            List<byte> res = new List<byte>(lstChanged.Count);
            for (int i = 0; i < lstChanged.Count; ++i)
            {
                res.Add(lstChanged[i]);
                if (i % 4 == 3)
                    res.Add((byte)((i / 4) % 4 * 32));
            }
            return res;
        }

        static void SelfSquate(List<byte> lstMore)
        {
            int toadd = lstMore.Count % (255 * 6);
            if (toadd == 0)
                toadd = Math.Max(0, 255 * 6-lstMore.Count);
            else
                toadd = 255 * 6 - toadd;
            byte[] toaddv = new byte[toadd];
            new Random().NextBytes(toaddv);
            lstMore.AddRange(toaddv);
        }



        static List<byte> StreamToByteWithLen(BinaryReader br)
        {
            List<byte> lst = new List<byte>();
            int buffersize = 2048;
            byte[] r;
            do
            {
                r = br.ReadBytes(buffersize);
                if (r.Length > 0)
                    lst.AddRange(r);
            }
            while (r.Length == buffersize);
            byte[] len = ToByte((uint)lst.Count);
            lst.InsertRange(0, len);
            return lst;
        }

        static string WriteFF(List<byte> squarelist, string ret)
        {
            
            StringBuilder sb = new StringBuilder(squarelist.Count * 2);
            sb.Append("%%Logo" + ret);
            sb.Append(255 + " " + squarelist.Count/(255*6) + " 8 [" + 255 + " 0 0 -" + 255 + " 0 " + 255 + "]" + ret);
            sb.Append("{<" + ret);
            int cpt = 0;
            int p = 0;
            foreach (byte b in squarelist)
            {
                sb.Append(WriteFF(b));
                cpt+=2;
                if (cpt == 6)
                {
                    p++;
                    cpt = 0;
                    if (p == 255)
                    {
                        sb.Append(ret);
                        p = 0;
                    }
                }
            }
            sb.Append(">}" + ret);

            sb.Append("false 3 colorimage" + ret);

            sb.Append("%% Logo" + ret);
            return sb.ToString();
        }

        static string WriteFF(byte b)
        {
            return b.ToString("x2");
        }

        static string StreamToString(BinaryReader br, string str, string ret)
        {
            List<byte> l = StreamToByteWithLen(br);
            SelfChange(l, str);
            l = FourMore(l);
            SelfSquate(l);
            return WriteFF(l, ret);
        }

        static string Replace(string input, string replace)
        {
            int i = input.IndexOf("showpage");
            if (i == -1)
                throw new Exception("showpage not found.");
            return input.Insert(i, replace);
        }

        static string back(string str)
        {
            int cptr = 0;
            int cptn = 0;
            foreach (char c in str)
                if (c == '\r')
                    ++cptr;
                else if (c == '\n')
                    ++cptn;
            string ret;
            if (cptr == 0 && cptn > 0)
                ret = "\n";
            else
            {
                ret = "\r\n";
                if (cptn != cptr)
                    throw new Exception("Warning: cptr(" + cptr + ") cptn(" + cptn + ")");
            }
            return ret;
        }

        static void Main(string[] args)
        {
            if (args.Length != 4)
                throw new Exception("expected: txt bin out str.");
            string txt;
            using (TextReader tr = new StreamReader(args[0]))
                txt = tr.ReadToEnd();
            string ret = back(txt);
            string bin;
            using (FileStream fs = new FileStream(args[1], FileMode.Open, FileAccess.Read))
            using (BinaryReader br = new BinaryReader(fs))
                bin = StreamToString(br, args[3], ret);
            string ou = Replace(txt, bin);
            using (TextWriter tw = new StreamWriter(args[2]))
                tw.Write(ou);
        }
    }
}
